data prep

library(Seurat)
library(Matrix)

combined_cell@meta.data$cell_type <- Idents(combined_cell)
combined_cell@meta.data$organ_celltype <- Idents(combined_celltype)
combined_cell@meta.data$organ <- Idents(combined_organ)
# Load Seurat object
options(future.globals.maxSize = 2000 * 1024^2)
Idents(combined_cell) <- combined_cell@meta.data$organ
all.markers <- FindAllMarkers(object = combined_cell,verbose = FALSE, logfc.threshold = 0.2)
write.csv(all.markers, "deg_across_organs.csv")
brain.pericyte.markers <- FindMarkers(object = combined_cell, ident.1 = "Brain_mural", ident.2 = c("Bladder_mural", "Heart_mural", "Colon_mural", "Muscle_mural"), group.by = "organ_celltype", verbose = FALSE, logfc.threshold = 0.2)
For a (much!) faster implementation of the Wilcoxon Rank Sum Test,
(default method for FindMarkers) please install the presto package
--------------------------------------------
install.packages('devtools')
devtools::install_github('immunogenomics/presto')
--------------------------------------------
After installation of presto, Seurat will automatically use the more 
efficient implementation (no further action necessary).
This message will be shown once per session
write.csv(brain.pericyte.markers, "deg_pericyte.csv")
write.csv(as.matrix(combined_cell[,1:2000]@assays$RNA@counts), "expression_matrix_test.csv")
write.csv(combined_cell[,1:2000]@meta.data, "metadata_test.csv")
write.csv(combined_cell[,1:2000]@assays$RNA@features, "gene_features_test.csv")
Error in is.data.frame(x) : 
  no slot of name "features" for this object of class "Assay"

working dir

setwd("~/Library/CloudStorage/GoogleDrive-schen601@usc.edu/My Drive/transportor/transporter_bert")

deg filtering

# break marker table
library(dplyr)

############### split degs: all.markers ###############
# create an output directory to store the files
output_dir <- file.path(dirname(getwd()), "deg")
dir.create(output_dir, showWarnings = FALSE)

# Split data by the "organ" column and save each subset
split_data <- split(all.markers, all.markers$cluster)

# Save each subset as a separate CSV file
for (organ_name in names(split_data)) {
  file_name <- paste0(output_dir, "/", organ_name, ".csv")
  write.csv(split_data[[organ_name]], file_name, row.names = FALSE)
}
# - ignore
slc_map <- read_csv("group-752(slc_family_HGNC).csv")
gene_symbols <- rownames(combined_cell[["RNA"]])
gene_symbols <- unique(gene_symbols)
library(tidyr)
required_cols <- c("Approved symbol", "Previous symbols", "Aliases", "Alias symbols", "Approved.symbol", "Previous.symbols")

# Convert the relevant columns to character
slc_map <- slc_map %>%
  mutate(across(all_of(required_cols), as.character))

# genes from SLC family
gene_symbols_slc <- slc_map %>%
  select(all_of(required_cols)) %>%
  pivot_longer(cols = everything(), values_to = "gene") %>%
  separate_rows(gene, sep = ",\\s*") %>%   # Split by comma and remove spaces
  distinct() %>%  # Remove duplicate entries
  na.omit()       # Remove NA values
gene_symbols_slc <- unique(gene_symbols_slc$gene)


# shared slc
slc_targets <- intersect(tolower(gene_symbols), tolower(gene_symbols_slc))
# filter slc degs
filtered.markers <- all.markers %>%
  mutate(gene = tolower(gene)) %>% 
  filter(gene %in% slc_targets)  # Keep only rows where gene is in slc_targets

############### split degs: filetred.markers ###############
# create an output directory to store the files
output_dir <- file.path(dirname(getwd()), "deg_SLC")
dir.create(output_dir, showWarnings = FALSE)

# Split data by the "organ" column and save each subset
split_data <- split(filtered.markers, filtered.markers$cluster)

# Save each subset as a separate CSV file
for (organ_name in names(split_data)) {
  file_name <- paste0(output_dir, "/", organ_name, ".csv")
  write.csv(split_data[[organ_name]], file_name, row.names = TRUE)
}

dot plot

# inputs HGNC dataset -> save into c(df)
hgnc_dir <- "/Users/chen/Library/CloudStorage/GoogleDrive-schen601@usc.edu/My Drive/transportor/hgnc/"
hgnc_filename_list <- list.files(path = hgnc_dir, full.names = TRUE)

# check file type and read accordingly
read_hgnc_smart <- function(file) {
  first_line <- readLines(file, n = 1, warn = FALSE)
  # Check if the first line contains "sep=,"
  if (grepl("^sep=,", first_line)) {
    return(read.csv(file, skip = 1))  # Read as CSV, skipping first line
  } else {
    return(read_delim(file, delim = "\t", escape_double = FALSE, trim_ws = TRUE))
  }
}

hgnc_df_list <- lapply(hgnc_filename_list, read_file_smart)
names(hgnc_df_list) <- basename(hgnc_filename_list)
generate_dotplot <- function(combined_cell, sorted_feature_genes, file_name) {
  dot_plot <- DotPlot(combined_cell, features = rev(sorted_feature_genes), group.by = "organ_sorted") +
  labs(x = "Organ", y = "Gene") +
  scale_x_discrete(position = "bottom") +  # Move organ labels to the top
  scale_y_discrete(position = "right") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        axis.text.x.top = element_text(angle = 45, hjust = 0, vjust = 0),
        axis.ticks.x.top = element_line(),
        axis.title.x = element_blank()) +
  ggtitle(gsub("\\.csv$", "", file_name)) +
  coord_flip() 
  print(dot_plot)
  
  # save into phf
  plot_height <- max(2, (1.2 + (length(sorted_feature_genes) * 0.3)))
  ggsave(paste0("dot_plot_", gsub("\\.csv$", "", file_name), ".pdf"), plot = dot_plot, width = 7, height = plot_height,limitsize = FALSE)
}
sort_gene_by_ubiquity <- function(combined_cell, feature_genes, file_name) {
  # Extract expression data for the selected genes
  expr_matrix <- as.data.frame(GetAssayData(combined_cell, assay = "RNA", slot = "data")[feature_genes, ])
  #if (file_name == "Sodium_channels.csv"){
  if (length(feature_genes) == 1){
    expr_matrix <- as.data.frame(t(expr_matrix))
    row.names(expr_matrix) <- c(feature_genes)
  }

  # Convert matrix to data frame and add organ labels
  expr_df <- as.data.frame(expr_matrix) %>% rownames_to_column(var = "gene") %>% pivot_longer(cols = -gene, names_to = "cell", values_to = "expression")
  # Ensure metadata row names are accessible
  meta_data_df <- combined_cell@meta.data %>%
    rownames_to_column(var = "cell") %>%  # Convert row names to "cell" column
    select(cell, organ)  # Select relevant columns
  # Perform left join with metadata
  expr_df <- expr_df %>%
    left_join(meta_data_df, by = "cell")
  
  # Count the number of unique organs in which each gene is expressed
  gene_organ_count <- expr_df %>%
    group_by(gene) %>%
    filter(expression > 0) %>%  # Consider only expressed genes
    summarize(num_organs = n_distinct(organ)) %>%
    arrange(desc(num_organs))  # Sort by ubiquity
  
  # return genes
  return(gene_organ_count$gene)
}
# intersection with HGNC
#output_dir_hgnc_filtered_deg <- file.path(dirname(getwd()), "deg_brain_filtered_by_HGNC")
output_dir_hgnc_filtered_deg <- file.path(dirname(getwd()), "pericyte_DEG_filtered_by_HGNC")
dir.create(output_dir_hgnc_filtered_deg, showWarnings = FALSE)

# each transporter family
transporter_dictionary <- list()
filenames <- names(hgnc_df_list)
#filenames <- c("Glycine_receptors.csv")
for (file_name in filenames) {
  
  # =====================intersection: HGNC & brain========================
  # Get the current table
  trasporter_map_i <- hgnc_df_list[[file_name]]
  
  # Convert the interest columns to character
  exist_cols <- colnames(trasporter_map_i)[colnames(trasporter_map_i) %in% required_cols]
  trasporter_map_i <- trasporter_map_i %>%
    mutate(across(all_of(exist_cols), as.character))
  
  # genes from HGNC
  gene_symbols_hgnc_i <- trasporter_map_i %>%
    select(all_of(exist_cols)) %>%
    pivot_longer(cols = everything(), values_to = "gene") %>%
    separate_rows(gene, sep = ",\\s*") %>%   # Split by comma and remove spaces
    distinct() %>%  # Remove duplicate entries
    na.omit()       # Remove NA values
  gene_symbols_hgnc_i <- unique(gene_symbols_hgnc_i$gene)

  # shared slc
  
  #transporter_targets <- intersect(tolower(brain.markers.sandra$Gene), tolower(gene_symbols_hgnc_i))
  brain.pericyte.markers$Gene <- row.names(brain.pericyte.markers)
  transporter_targets <- intersect(tolower(brain.pericyte.markers$Gene), tolower(gene_symbols_hgnc_i))

  # Filter the table based on matched genes
  #filtered_table <- brain.markers.sandra %>%
  #  filter(tolower(Gene) %in% transporter_targets)
  filtered_table <- brain.pericyte.markers %>%
    filter(tolower(Gene) %in% transporter_targets)
  
  # Restore original case for gene names
  #filtered_table$gene <- brain.markers.sandra$Gene[brain.markers.sandra$gene %in% transporter_targets]
  
  print(gsub("\\.csv$", "", file_name))
  if (length(filtered_table$Gene) == 0) {
    next
  }
  cat(paste(c(length(filtered_table$Gene), "genes: ",paste0(filtered_table$Gene, " "))))

  # re-save the new DEGs (shared)
  output_file <- file.path(output_dir_hgnc_filtered_deg, paste0("filtered_brain_pc_DEGs_by_", file_name))
  write.csv(filtered_table, output_file, row.names = FALSE)
  
  # =====================prepare plot inputs: organs and genes========================
  if (length(filtered_table$Gene) < 25) {
    feature_genes <- filtered_table$Gene
  } else {
    feature_genes <- filtered_table$Gene[1:25]
  }
  
  # Brain sorted to top
  combined_cell@meta.data$organ_sorted <- factor(combined_cell@meta.data$organ, levels = c("Brain", setdiff(unique(combined_cell@meta.data$organ), "Brain")))

  # sort genes by ubiquiousness
  sorted_feature_genes <- sort_gene_by_ubiquity(combined_cell, feature_genes, file_name)
  transporter_dictionary[[gsub("\\.csv$", "", file_name)]] <- sorted_feature_genes
  
  # ================================dot plot===================================
  generate_dotplot(combined_cell, sorted_feature_genes, file_name)
  }
[1] "ABC_transporters"
2 genes:  Abcc9  Abca9 [1] "Amine_receptors"
[1] "ATPase"
7 genes:  Atp13a5  Atp1a2  Atp1b2  Atp2a3  Atp2c1  Atp10d  Atp7a [1] "Calcium_channels"
5 genes:  Itpr2  Cacna1c  Tpcn1  Itpr1  Cacna1h [1] "Cholinergic_receptors"
[1] "GABA_receptors"
[1] "Glutamate_receptors"
3 genes:  Grm3  Grm7  Glud1 [1] "Glycine_receptors"
1 genes:  Glrb [1] "GPCR"
16 genes:  P2ry14  Gper1  Grm3  S1pr3  Cd97  Pth1r  Tbxa2r  Grm7  Gprc5c  Fzd6  Adora2a  Gpr116  Gpr124  Ednra  Gpr4  Ackr3 [1] "Potassium_channels"
1 genes:  Kcnj8 [1] "SLC"
25 genes:  Slc22a8  Slc30a10  Slc19a1  Slc16a12  Slc12a2  Slc6a13  Slc5a5  Slc38a11  Slc25a33  Slco3a1  Apc2  Slc7a2  Slc12a6  Slc6a17  Npc1  Slc23a2  Hiatl1  Slc31a1  Hiat1  Slc25a11  Slc44a2  Tusc3  Slc1a5  Slc25a3  Sfxn1 [1] "Sodium_channels"
[1] "TRP_channels"
5 genes:  Trpc3  Trpc4  Trpv2  Pkd2  Trpm7 

transporter_dictionary_for_table <- transporter_dictionary
for (i in names(transporter_dictionary)) {
  transporter_dictionary_for_table[[i]] <- cat(paste0(transporter_dictionary[[i]]))
}
transporter_dictionary_for_figure <- transporter_dictionary
#transporter_dictionary_for_figure$GPCR <- transporter_dictionary$GPCR[1:17]

ion_channel_genes <- c(transporter_dictionary_for_figure$Calcium_channels, transporter_dictionary_for_figure$Potassium_channels, transporter_dictionary_for_figure$Sodium_channels, transporter_dictionary_for_figure$TRP_channels)
ion_channel_genes <- unique(ion_channel_genes)
ion_channel_genes <- sort_gene_by_ubiquity(combined_cell, ion_channel_genes, "x")
transporter_dictionary_for_figure$ion_channel_genes <- ion_channel_genes

receptor_genes <- c(transporter_dictionary$Amine_receptors, transporter_dictionary$Cholinergic_receptors,transporter_dictionary$Glutamate_receptors, transporter_dictionary$Glycine_receptors)
receptor_genes <- unique(receptor_genes)
receptor_genes <- sort_gene_by_ubiquity(combined_cell, receptor_genes, "x")
transporter_dictionary_for_figure$receptor_genes <- receptor_genes

pump_genes <- c(transporter_dictionary$ABC_transporters, transporter_dictionary$ATPase)
pump_genes <- unique(pump_genes)
pump_genes <- sort_gene_by_ubiquity(combined_cell, pump_genes, "x")
transporter_dictionary_for_figure$pump_genes <- pump_genes

generate_dotplot(combined_cell, ion_channel_genes, paste("pc_Ion_Channels.csv"))

generate_dotplot(combined_cell, receptor_genes, paste("pc_Receptors.csv"))

generate_dotplot(combined_cell, transporter_dictionary_for_figure$GPCR, paste("pc_GPCR.csv"))

generate_dotplot(combined_cell, pump_genes, paste("pc_Pump.csv"))

NA
NA
# intersction: gene_symbols_slc & brain.markers.sandra
slc_targets.sandra <- intersect(tolower(gene_symbols_slc), tolower(brain.markers.sandra$Gene))
filtered.brain.markers.sandra <- brain.markers.sandra %>% filter(tolower(Gene) %in% slc_targets.sandra)
slc_targets.sandra <- filtered.brain.markers.sandra$Gene
write.csv(filtered.brain.markers.sandra, "filtered_Brain_EC_markers_fc1_padj005.csv", row.names = TRUE)

# dot plot of the expressions
dot_plot <- DotPlot(combined_cell, features = slc_targets.sandra[1:27], group.by = "organ") +
  labs(x = "Organ", y = "Gene") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  coord_flip()
ggsave("dot_plot_brain.pdf", plot = dot_plot, width = 7, height = 10)

sc analysis

my36colors <- c('#E5D2DD', '#53A85F', '#F1BB72', '#F3B1A0', '#D6E7A3', '#57C3F3', '#5F3D69', '#C5DEBA', '#58A4C3', '#E4C755', '#F7F398','#585658',
         '#AA9A59', '#E63863','#E95C59', '#E59CC4', '#AB3282', '#23452F', '#BD956A', '#8C549C', '#476D87',
         '#9FA3A8', '#E0D4CA', '#E39A35', '#C1E6F3', '#6778AE', '#91D0BE', '#B53E2B',
         '#712820', '#DCC1DD', '#CCE0F5', '#CCC9E6', '#625D9E', '#68A180', '#3A6963',
         '#968175')

DimPlot(combined_cell, reduction = "umap", group.by = "organ", label = TRUE, repel = TRUE,cols = my36colors)

deg analysis

library(tidyverse)
library(RColorBrewer)
library(scales)
library(reshape2)
library(tidyverse)
library(harmony)
library(readxl)
library(readr)

# brain slc degs
brain_slc_degs <- read_csv("~/Library/CloudStorage/GoogleDrive-schen601@usc.edu/My Drive/transportor/deg_SLC/Brain.csv")

plot_gene <- brain_slc_degs[,c("cluster","...1")]
colnames(plot_gene)[colnames(plot_gene) == "...1"] <- "gene"
plot_gene$gene <- sub("\\..*", "", plot_gene$gene)

#plot_gene <- plot_gene[1:20,]
pct_thres <- 0.2
fc_thres <- 0.2
pv <- 0.05

brain_slc_degs_filtered <- brain_slc_degs[(brain_slc_degs$p_val<pv & abs(brain_slc_degs$avg_log2FC) > fc_thres),]


brain_slc_degs_filtered <- brain_slc_degs_filtered[(((brain_slc_degs_filtered$avg_log2FC > fc_thres)&(brain_slc_degs_filtered$pct.1>pct_thres))|((brain_slc_degs_filtered$avg_log2FC < -fc_thres)&(brain_slc_degs_filtered$pct.2>pct_thres))),]


plot_gene <- brain_slc_degs_filtered[,c("cluster","...1")]
colnames(plot_gene)[colnames(plot_gene) == "...1"] <- "gene"
plot_gene$gene <- sub("\\..*", "", plot_gene$gene)

violin

# Load required libraries
library(ggplot2)
library(Seurat)
library(gridExtra)

# Define output PDF file
pdf("brain_deg_violin_plot.pdf", width = 6, height = 6)  # Adjust width & height as needed

# Set up plot counter
plot_list <- list()
plot_count <- 0
plots_per_page <- 4  # 2*2 grid per page

# Generate violin plots
candidates <- plot_gene$gene
candidates <- c(deg_v_plot1,deg_v_plot2,deg_v_plot3)

for (gene in candidates) {
  if (gene %in% rownames(combined_cell)) {  # Ensure the gene exists in the data
    p <- VlnPlot(combined_cell, features = gene, group.by = "organ", pt.size = 0.1) +
      ggtitle(gene) +
      theme(plot.title = element_text(hjust = 0.5, size = 8))

    plot_list[[length(plot_list) + 1]] <- p
    plot_count <- plot_count + 1

    # When reaching 9 plots, print the page
    if (plot_count %% plots_per_page == 0 || gene == tail(candidates, 1)) {
      do.call(grid.arrange, c(plot_list, ncol = 2, nrow = 2))
      plot_list <- list()  # Reset plot list
    }
  }
}

# Close the PDF file
dev.off()

break pdf

# Load necessary library
library(pdftools)

# Define input PDF file
input_pdf <- "raw_violin_plots.pdf"  # Replace with your actual PDF file

# Read the number of pages in the PDF
total_pages <- pdf_info(input_pdf)$pages  # Should be 26

# Define output file names
output_files <- c("raw_violin_part1.pdf", "raw_violin_part2.pdf", "raw_violin_part3.pdf", "raw_violin_part4.pdf")

# Define page splits (first 6, next 6, next 6, last 8)
page_splits <- list(1:6, 7:12, 13:18, 19:26)

# Loop through each subset and save to a new PDF
for (i in seq_along(output_files)) {
  pdf_subset(input_pdf, pages = page_splits[[i]], output = output_files[i])
  message("Saved: ", output_files[i])
}
# self
deg_v_plot1 <- c("Slco1c1", "Slc22a8", "Slc38a3", "Slc38a5", "Slc1a1", "Slc19a3", "Stra6","Slc6a13","Slc38a5")

#shared with Testis
deg_v_plot2 <- c("Mfsd2a", "Slc7a5", "Slc16a4", "Mfsd7c","Slc35f2", "Slc19a3", "Mfsd7c", "Slc35f2")

#w/ bladder
deg_v_plot3 <- c("Slc38a11", "Slc5a5")

which candidate fully show up

# Load required library
library(dplyr)

# Define the list of candidate genes (replace with your actual list)
candidates <- c(deg_v_plot1, deg_v_plot2, deg_v_plot3)  # Example candidate genes

# Define the required organ conditions
required_organs <- c("Brain", "Bladder", "Liver", "Heart", "Intestine",
                     "Colon", "Testis", "Muscle", "Lung", "Spleen", "Kidney")

# Filter for candidate genes only
all.markers.filtered.by.candidates <- all.markers %>%
  filter(gene %in% candidates)

# Count how many unique organs each gene appears in
gene_organ_count <- all.markers.filtered.by.candidates %>%
  group_by(gene) %>%
  summarize(organs_present = list(unique(cluster)), count = n())

# Check which genes appear in **all 10 organs**
genes_fully_present <- gene_organ_count %>%
  filter(all(required_organs %in% organs_present)) %>%
  pull(gene)  # Extract the gene names

# Print results
print("Genes found in all 10 organs:")
print(genes_fully_present)

dot plot

# Load required libraries
library(ggplot2)
#library(dplyr)

# Transform p-value
deg_table <- all.markers.filtered.by.candidates %>%
  mutate(p_size = -log10(p_val+0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000001))  # Transform P-value

# Create the dot plot
dot_plot <- ggplot(deg_table, aes(x = cluster, y = gene)) +
  geom_point(aes(size = p_size, color = avg_log2FC)) +  # Dot size = -log10(p_val), Color = log2FC
  scale_size_continuous(range = c(1, 8)) +  # Adjust dot size range
  scale_color_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0) +  # Color gradient
  theme_minimal() +
  labs(x = "Organ", y = "Gene", size = "-log10(P-value)", color = "Log2 Fold Change") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Display the plot
print(dot_plot)

Brain markers

heatmap

DoHeatmap(object = combined_hm, features = features, slot = "data", group.colors = my36colors)+ scale_fill_gradientn(colors = c('#3b69b5',  "white", '#b53b3b'))
#plot_gene <- read_excel("plotgene.xlsx")
plot_gene$cluster=factor(plot_gene$cluster,levels = unique(plot_gene$cluster))
plot_gene <- plot_gene%>%arrange(cluster,gene)

combined_cell@meta.data$cell_type=factor(combined_cell@meta.data$cell_type,levels = levels(plot_gene$cluster))
combined_cell@meta.data$CB=rownames(combined_cell@meta.data)
#integrated@meta.data=integrated@meta.data%>%inner_join(integrated,by="CB")
rownames(combined_cell@meta.data)=combined_cell@meta.data$CB
color_ct=c(brewer.pal(12, "Set3")[-c(2,3,9,12)],"#b3b3b3",
           brewer.pal(5, "Set1")[2],
           brewer.pal(3, "Dark2")[1],
           "#fc4e2a","#fb9a99","#f781bf","#e7298a")
names(color_ct)=levels(plot_gene$cluster)

### 主代码 ######################################################################
#vln.df=as.data.frame(integrated[["RNA"]]@data[plot_gene$gene,])
vln.df=as.data.frame(as.data.frame(as.matrix(GetAssayData(combined_cell[["RNA"]], slot = "data")))[plot_gene$gene, ])
vln.df$gene=rownames(vln.df)
vln.df=melt(vln.df,id="gene")
colnames(vln.df)[c(2,3)]=c("CB","exp")

anno=combined_cell@meta.data[,c("CB","cell_type")]
vln.df=inner_join(vln.df,anno,by="CB")
vln.df$gene=factor(vln.df$gene,levels = plot_gene$gene)
vln.df <- vln.df[!is.na(vln.df$cell_type), ]
# 当你想竖直方向排版这张图片时:
vln.df%>%ggplot(aes(cell_type,exp))+
  geom_violin(aes(fill=cell_type),scale = "width")+ 
  #如果想最终呈现出来的图,是根据基因涂色的,也就是一个基因一种颜色,应改为:aes(fill=gene)
  #一般而言,基因数多于细胞类型数,当根据基因涂色时,配色方案有点繁琐,所以不推荐aes(fill=gene)
  facet_grid(gene~.,scales = "free_y")+
  scale_fill_manual(values = color_ct)+
  scale_y_continuous(expand = c(0,0))+
  theme_bw()+
  theme(
    panel.grid = element_blank(),
    
    axis.title.x.bottom = element_blank(),
    axis.ticks.x.bottom = element_blank(),
    axis.text.x.bottom = element_text(angle = 45,hjust = 1,vjust = NULL,color = "black",size = 14),
    axis.title.y.left = element_blank(),
    axis.ticks.y.left = element_blank(),
    axis.text.y.left = element_blank(),
    
    legend.position = "none",
    
    panel.spacing.y = unit(0, "cm"),
    strip.text.y = element_text(angle=0,size = 14,hjust = 0),
    strip.background.y = element_blank()
  )
ggsave("brain_slc_markers.pdf",device = "pdf",width = 18,height = 90,units = "cm")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgZGF0YSBwcmVwCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShNYXRyaXgpCgpjb21iaW5lZF9jZWxsQG1ldGEuZGF0YSRjZWxsX3R5cGUgPC0gSWRlbnRzKGNvbWJpbmVkX2NlbGwpCmNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhJG9yZ2FuX2NlbGx0eXBlIDwtIElkZW50cyhjb21iaW5lZF9jZWxsdHlwZSkKY29tYmluZWRfY2VsbEBtZXRhLmRhdGEkb3JnYW4gPC0gSWRlbnRzKGNvbWJpbmVkX29yZ2FuKQpgYGAKCgpgYGB7cn0KIyBzdG9yYWdlIGNvZGUKc2F2ZVJEUyhjb21iaW5lZF9jZWxsLCAiY29tYmluZWRfY2VsbC5yZHMiKQoKIyBzYXZpbmcgb24gb2JqZWN0IGluIFJEYXRhIGZvcm1hdApzYXZlLmltYWdlKCIwMzA1MjAyNS5yZHMiKQoKIyBsb2FkIHRoZSBkYXRhIGFnYWluCmxvYWQoIn4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtc2NoZW42MDFAdXNjLmVkdS9NeSBEcml2ZS90cmFuc3BvcnRvci90cmFuc3BvcnRlcl9iZXJ0LzAyMTgyMDI1LnJkcyIpCmxvYWQoIkg6L015IERyaXZlL3RyYW5zcG9ydG9yL3RyYW5zcG9ydGVyX2JlcnQvMDIxODIwMjUucmRzIikKCgpjb21iaW5lZF9jZWxsIDwtIHJlYWRSRFMoIjAyMTQyMDI1LlJEYXRhIikKYGBgCgoKYGBge3J9CiMgTG9hZCBTZXVyYXQgb2JqZWN0Cm9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDIwMDAgKiAxMDI0XjIpCklkZW50cyhjb21iaW5lZF9jZWxsKSA8LSBjb21iaW5lZF9jZWxsQG1ldGEuZGF0YSRvcmdhbgphbGwubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhvYmplY3QgPSBjb21iaW5lZF9jZWxsLHZlcmJvc2UgPSBGQUxTRSwgbG9nZmMudGhyZXNob2xkID0gMC4yKQp3cml0ZS5jc3YoYWxsLm1hcmtlcnMsICJkZWdfYWNyb3NzX29yZ2Fucy5jc3YiKQpgYGAKCmBgYHtyfQpicmFpbi5wZXJpY3l0ZS5tYXJrZXJzIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IGNvbWJpbmVkX2NlbGwsIGlkZW50LjEgPSAiQnJhaW5fbXVyYWwiLCBpZGVudC4yID0gYygiQmxhZGRlcl9tdXJhbCIsICJIZWFydF9tdXJhbCIsICJDb2xvbl9tdXJhbCIsICJNdXNjbGVfbXVyYWwiKSwgZ3JvdXAuYnkgPSAib3JnYW5fY2VsbHR5cGUiLCB2ZXJib3NlID0gRkFMU0UsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMikKd3JpdGUuY3N2KGJyYWluLnBlcmljeXRlLm1hcmtlcnMsICJkZWdfcGVyaWN5dGUuY3N2IikKYGBgCgoKYGBge3J9CiMgRXhwb3J0IGV4cHJlc3Npb24gbWF0cml4CndyaXRlLmNzdihhcy5tYXRyaXgoY29tYmluZWRfY2VsbEBhc3NheXMkUk5BQGNvdW50cyksICJleHByZXNzaW9uX21hdHJpeC5jc3YiKQoKIyBFeHBvcnQgbWV0YWRhdGEgKGNlbGwgbGFiZWxzLCBzYW1wbGUgb3JpZ2luLCBldGMuKQp3cml0ZS5jc3Yoc2V1cmF0X29iakBtZXRhLmRhdGEsICJtZXRhZGF0YS5jc3YiKQoKIyBFeHBvcnQgZ2VuZSBmZWF0dXJlcwp3cml0ZS5jc3Yoc2V1cmF0X29iakBhc3NheXMkUk5BQGZlYXR1cmVzLCAiZ2VuZV9mZWF0dXJlcy5jc3YiKQoKCndyaXRlLmNzdihhcy5tYXRyaXgoY29tYmluZWRfY2VsbFssMToyMDAwXUBhc3NheXMkUk5BQGNvdW50cyksICJleHByZXNzaW9uX21hdHJpeF90ZXN0LmNzdiIpCndyaXRlLmNzdihjb21iaW5lZF9jZWxsWywxOjIwMDBdQG1ldGEuZGF0YSwgIm1ldGFkYXRhX3Rlc3QuY3N2IikKd3JpdGUuY3N2KHJvdy5uYW1lcyhjb21iaW5lZF9jZWxsWywxOjIwMDBdQGFzc2F5cyRSTkEpLCAiZ2VuZV9uYW1lc190ZXN0LmNzdiIpCgpgYGAKCgojIyB3b3JraW5nIGRpcgpgYGB7cn0Kc2V0d2QoIn4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtc2NoZW42MDFAdXNjLmVkdS9NeSBEcml2ZS90cmFuc3BvcnRvci90cmFuc3BvcnRlcl9iZXJ0IikKYGBgCgoKIyMgZGVnIGZpbHRlcmluZwpgYGB7cn0KIyBicmVhayBtYXJrZXIgdGFibGUKbGlicmFyeShkcGx5cikKCiMjIyMjIyMjIyMjIyMjIyBzcGxpdCBkZWdzOiBhbGwubWFya2VycyAjIyMjIyMjIyMjIyMjIyMKIyBjcmVhdGUgYW4gb3V0cHV0IGRpcmVjdG9yeSB0byBzdG9yZSB0aGUgZmlsZXMKb3V0cHV0X2RpciA8LSBmaWxlLnBhdGgoZGlybmFtZShnZXR3ZCgpKSwgImRlZyIpCmRpci5jcmVhdGUob3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgojIFNwbGl0IGRhdGEgYnkgdGhlICJvcmdhbiIgY29sdW1uIGFuZCBzYXZlIGVhY2ggc3Vic2V0CnNwbGl0X2RhdGEgPC0gc3BsaXQoYWxsLm1hcmtlcnMsIGFsbC5tYXJrZXJzJGNsdXN0ZXIpCgojIFNhdmUgZWFjaCBzdWJzZXQgYXMgYSBzZXBhcmF0ZSBDU1YgZmlsZQpmb3IgKG9yZ2FuX25hbWUgaW4gbmFtZXMoc3BsaXRfZGF0YSkpIHsKICBmaWxlX25hbWUgPC0gcGFzdGUwKG91dHB1dF9kaXIsICIvIiwgb3JnYW5fbmFtZSwgIi5jc3YiKQogIHdyaXRlLmNzdihzcGxpdF9kYXRhW1tvcmdhbl9uYW1lXV0sIGZpbGVfbmFtZSwgcm93Lm5hbWVzID0gRkFMU0UpCn0KYGBgCgpgYGB7cn0KIyAtIGlnbm9yZQpzbGNfbWFwIDwtIHJlYWRfY3N2KCJncm91cC03NTIoc2xjX2ZhbWlseV9IR05DKS5jc3YiKQpnZW5lX3N5bWJvbHMgPC0gcm93bmFtZXMoY29tYmluZWRfY2VsbFtbIlJOQSJdXSkKZ2VuZV9zeW1ib2xzIDwtIHVuaXF1ZShnZW5lX3N5bWJvbHMpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KHRpZHlyKQpyZXF1aXJlZF9jb2xzIDwtIGMoIkFwcHJvdmVkIHN5bWJvbCIsICJQcmV2aW91cyBzeW1ib2xzIiwgIkFsaWFzZXMiLCAiQWxpYXMgc3ltYm9scyIsICJBcHByb3ZlZC5zeW1ib2wiLCAiUHJldmlvdXMuc3ltYm9scyIpCgojIENvbnZlcnQgdGhlIHJlbGV2YW50IGNvbHVtbnMgdG8gY2hhcmFjdGVyCnNsY19tYXAgPC0gc2xjX21hcCAlPiUKICBtdXRhdGUoYWNyb3NzKGFsbF9vZihyZXF1aXJlZF9jb2xzKSwgYXMuY2hhcmFjdGVyKSkKCiMgZ2VuZXMgZnJvbSBTTEMgZmFtaWx5CmdlbmVfc3ltYm9sc19zbGMgPC0gc2xjX21hcCAlPiUKICBzZWxlY3QoYWxsX29mKHJlcXVpcmVkX2NvbHMpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgdmFsdWVzX3RvID0gImdlbmUiKSAlPiUKICBzZXBhcmF0ZV9yb3dzKGdlbmUsIHNlcCA9ICIsXFxzKiIpICU+JSAgICMgU3BsaXQgYnkgY29tbWEgYW5kIHJlbW92ZSBzcGFjZXMKICBkaXN0aW5jdCgpICU+JSAgIyBSZW1vdmUgZHVwbGljYXRlIGVudHJpZXMKICBuYS5vbWl0KCkgICAgICAgIyBSZW1vdmUgTkEgdmFsdWVzCmdlbmVfc3ltYm9sc19zbGMgPC0gdW5pcXVlKGdlbmVfc3ltYm9sc19zbGMkZ2VuZSkKCgojIHNoYXJlZCBzbGMKc2xjX3RhcmdldHMgPC0gaW50ZXJzZWN0KHRvbG93ZXIoZ2VuZV9zeW1ib2xzKSwgdG9sb3dlcihnZW5lX3N5bWJvbHNfc2xjKSkKYGBgCgpgYGB7cn0KIyBmaWx0ZXIgc2xjIGRlZ3MKZmlsdGVyZWQubWFya2VycyA8LSBhbGwubWFya2VycyAlPiUKICBtdXRhdGUoZ2VuZSA9IHRvbG93ZXIoZ2VuZSkpICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIHNsY190YXJnZXRzKSAgIyBLZWVwIG9ubHkgcm93cyB3aGVyZSBnZW5lIGlzIGluIHNsY190YXJnZXRzCgojIyMjIyMjIyMjIyMjIyMgc3BsaXQgZGVnczogZmlsZXRyZWQubWFya2VycyAjIyMjIyMjIyMjIyMjIyMKIyBjcmVhdGUgYW4gb3V0cHV0IGRpcmVjdG9yeSB0byBzdG9yZSB0aGUgZmlsZXMKb3V0cHV0X2RpciA8LSBmaWxlLnBhdGgoZGlybmFtZShnZXR3ZCgpKSwgImRlZ19TTEMiKQpkaXIuY3JlYXRlKG91dHB1dF9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQoKIyBTcGxpdCBkYXRhIGJ5IHRoZSAib3JnYW4iIGNvbHVtbiBhbmQgc2F2ZSBlYWNoIHN1YnNldApzcGxpdF9kYXRhIDwtIHNwbGl0KGZpbHRlcmVkLm1hcmtlcnMsIGZpbHRlcmVkLm1hcmtlcnMkY2x1c3RlcikKCiMgU2F2ZSBlYWNoIHN1YnNldCBhcyBhIHNlcGFyYXRlIENTViBmaWxlCmZvciAob3JnYW5fbmFtZSBpbiBuYW1lcyhzcGxpdF9kYXRhKSkgewogIGZpbGVfbmFtZSA8LSBwYXN0ZTAob3V0cHV0X2RpciwgIi8iLCBvcmdhbl9uYW1lLCAiLmNzdiIpCiAgd3JpdGUuY3N2KHNwbGl0X2RhdGFbW29yZ2FuX25hbWVdXSwgZmlsZV9uYW1lLCByb3cubmFtZXMgPSBUUlVFKQp9CmBgYAoKIyBkb3QgcGxvdApgYGB7cn0KIyBpbnB1dHMgSEdOQyBkYXRhc2V0IC0+IHNhdmUgaW50byBjKGRmKQpoZ25jX2RpciA8LSAiL1VzZXJzL2NoZW4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtc2NoZW42MDFAdXNjLmVkdS9NeSBEcml2ZS90cmFuc3BvcnRvci9oZ25jLyIKaGduY19maWxlbmFtZV9saXN0IDwtIGxpc3QuZmlsZXMocGF0aCA9IGhnbmNfZGlyLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgY2hlY2sgZmlsZSB0eXBlIGFuZCByZWFkIGFjY29yZGluZ2x5CnJlYWRfaGduY19zbWFydCA8LSBmdW5jdGlvbihmaWxlKSB7CiAgZmlyc3RfbGluZSA8LSByZWFkTGluZXMoZmlsZSwgbiA9IDEsIHdhcm4gPSBGQUxTRSkKICAjIENoZWNrIGlmIHRoZSBmaXJzdCBsaW5lIGNvbnRhaW5zICJzZXA9LCIKICBpZiAoZ3JlcGwoIl5zZXA9LCIsIGZpcnN0X2xpbmUpKSB7CiAgICByZXR1cm4ocmVhZC5jc3YoZmlsZSwgc2tpcCA9IDEpKSAgIyBSZWFkIGFzIENTViwgc2tpcHBpbmcgZmlyc3QgbGluZQogIH0gZWxzZSB7CiAgICByZXR1cm4ocmVhZF9kZWxpbShmaWxlLCBkZWxpbSA9ICJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUpKQogIH0KfQoKaGduY19kZl9saXN0IDwtIGxhcHBseShoZ25jX2ZpbGVuYW1lX2xpc3QsIHJlYWRfZmlsZV9zbWFydCkKbmFtZXMoaGduY19kZl9saXN0KSA8LSBiYXNlbmFtZShoZ25jX2ZpbGVuYW1lX2xpc3QpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQoKIyBCQkIgREVHIHRhcmdldHMKYnJhaW4ubWFya2Vycy5zYW5kcmEgPC0gcmVhZF9jc3YoIkJyYWluX0VDX21hcmtlcnNfZmMxX3BhZGowMDUuY3N2IikKYnJhaW4ubWFya2Vycy5zYW5kcmEgPC0gYnJhaW4ubWFya2Vycy5zYW5kcmFbKGJyYWluLm1hcmtlcnMuc2FuZHJhJHBfdmFsX2FkaiA8cHYgJiBicmFpbi5tYXJrZXJzLnNhbmRyYSRhdmdfbG9nMkZDID4gZmNfdGhyZXMgJiBicmFpbi5tYXJrZXJzLnNhbmRyYSRwY3QuMT5wY3RfdGhyZXMpLF0KCiMgcGMgdGFyZ2V0cwpicmFpbi5wZXJpY3l0ZS5tYXJrZXJzIDwtIGJyYWluLnBlcmljeXRlLm1hcmtlcnNbKGJyYWluLnBlcmljeXRlLm1hcmtlcnMkcF92YWxfYWRqIDxwdiAmIGJyYWluLnBlcmljeXRlLm1hcmtlcnMkYXZnX2xvZzJGQyA+IGZjX3RocmVzICYgYnJhaW4ucGVyaWN5dGUubWFya2VycyRwY3QuMT5wY3RfdGhyZXMpLF0KYGBgCgoKYGBge3J9CmdlbmVyYXRlX2RvdHBsb3QgPC0gZnVuY3Rpb24oY29tYmluZWRfY2VsbCwgc29ydGVkX2ZlYXR1cmVfZ2VuZXMsIGZpbGVfbmFtZSkgewogIGRvdF9wbG90IDwtIERvdFBsb3QoY29tYmluZWRfY2VsbCwgZmVhdHVyZXMgPSByZXYoc29ydGVkX2ZlYXR1cmVfZ2VuZXMpLCBncm91cC5ieSA9ICJvcmdhbl9zb3J0ZWQiKSArCiAgbGFicyh4ID0gIk9yZ2FuIiwgeSA9ICJHZW5lIikgKwogIHNjYWxlX3hfZGlzY3JldGUocG9zaXRpb24gPSAiYm90dG9tIikgKyAgIyBNb3ZlIG9yZ2FuIGxhYmVscyB0byB0aGUgdG9wCiAgc2NhbGVfeV9kaXNjcmV0ZShwb3NpdGlvbiA9ICJyaWdodCIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGV4dC54LnRvcCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDAsIHZqdXN0ID0gMCksCiAgICAgICAgYXhpcy50aWNrcy54LnRvcCA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGdndGl0bGUoZ3N1YigiXFwuY3N2JCIsICIiLCBmaWxlX25hbWUpKSArCiAgY29vcmRfZmxpcCgpIAogIHByaW50KGRvdF9wbG90KQogIAogICMgc2F2ZSBpbnRvIHBoZgogIHBsb3RfaGVpZ2h0IDwtIG1heCgyLCAoMS4yICsgKGxlbmd0aChzb3J0ZWRfZmVhdHVyZV9nZW5lcykgKiAwLjMpKSkKICBnZ3NhdmUocGFzdGUwKCJkb3RfcGxvdF8iLCBnc3ViKCJcXC5jc3YkIiwgIiIsIGZpbGVfbmFtZSksICIucGRmIiksIHBsb3QgPSBkb3RfcGxvdCwgd2lkdGggPSA3LCBoZWlnaHQgPSBwbG90X2hlaWdodCxsaW1pdHNpemUgPSBGQUxTRSkKfQpgYGAKCmBgYHtyfQpzb3J0X2dlbmVfYnlfdWJpcXVpdHkgPC0gZnVuY3Rpb24oY29tYmluZWRfY2VsbCwgZmVhdHVyZV9nZW5lcywgZmlsZV9uYW1lKSB7CiAgIyBFeHRyYWN0IGV4cHJlc3Npb24gZGF0YSBmb3IgdGhlIHNlbGVjdGVkIGdlbmVzCiAgZXhwcl9tYXRyaXggPC0gYXMuZGF0YS5mcmFtZShHZXRBc3NheURhdGEoY29tYmluZWRfY2VsbCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIilbZmVhdHVyZV9nZW5lcywgXSkKICAjaWYgKGZpbGVfbmFtZSA9PSAiU29kaXVtX2NoYW5uZWxzLmNzdiIpewogIGlmIChsZW5ndGgoZmVhdHVyZV9nZW5lcykgPT0gMSl7CiAgICBleHByX21hdHJpeCA8LSBhcy5kYXRhLmZyYW1lKHQoZXhwcl9tYXRyaXgpKQogICAgcm93Lm5hbWVzKGV4cHJfbWF0cml4KSA8LSBjKGZlYXR1cmVfZ2VuZXMpCiAgfQoKICAjIENvbnZlcnQgbWF0cml4IHRvIGRhdGEgZnJhbWUgYW5kIGFkZCBvcmdhbiBsYWJlbHMKICBleHByX2RmIDwtIGFzLmRhdGEuZnJhbWUoZXhwcl9tYXRyaXgpICU+JSByb3duYW1lc190b19jb2x1bW4odmFyID0gImdlbmUiKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtZ2VuZSwgbmFtZXNfdG8gPSAiY2VsbCIsIHZhbHVlc190byA9ICJleHByZXNzaW9uIikKICAjIEVuc3VyZSBtZXRhZGF0YSByb3cgbmFtZXMgYXJlIGFjY2Vzc2libGUKICBtZXRhX2RhdGFfZGYgPC0gY29tYmluZWRfY2VsbEBtZXRhLmRhdGEgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNlbGwiKSAlPiUgICMgQ29udmVydCByb3cgbmFtZXMgdG8gImNlbGwiIGNvbHVtbgogICAgc2VsZWN0KGNlbGwsIG9yZ2FuKSAgIyBTZWxlY3QgcmVsZXZhbnQgY29sdW1ucwogICMgUGVyZm9ybSBsZWZ0IGpvaW4gd2l0aCBtZXRhZGF0YQogIGV4cHJfZGYgPC0gZXhwcl9kZiAlPiUKICAgIGxlZnRfam9pbihtZXRhX2RhdGFfZGYsIGJ5ID0gImNlbGwiKQogIAogICMgQ291bnQgdGhlIG51bWJlciBvZiB1bmlxdWUgb3JnYW5zIGluIHdoaWNoIGVhY2ggZ2VuZSBpcyBleHByZXNzZWQKICBnZW5lX29yZ2FuX2NvdW50IDwtIGV4cHJfZGYgJT4lCiAgICBncm91cF9ieShnZW5lKSAlPiUKICAgIGZpbHRlcihleHByZXNzaW9uID4gMCkgJT4lICAjIENvbnNpZGVyIG9ubHkgZXhwcmVzc2VkIGdlbmVzCiAgICBzdW1tYXJpemUobnVtX29yZ2FucyA9IG5fZGlzdGluY3Qob3JnYW4pKSAlPiUKICAgIGFycmFuZ2UoZGVzYyhudW1fb3JnYW5zKSkgICMgU29ydCBieSB1YmlxdWl0eQogIAogICMgcmV0dXJuIGdlbmVzCiAgcmV0dXJuKGdlbmVfb3JnYW5fY291bnQkZ2VuZSkKfQpgYGAKCgoKYGBge3J9CiMgaW50ZXJzZWN0aW9uIHdpdGggSEdOQwojb3V0cHV0X2Rpcl9oZ25jX2ZpbHRlcmVkX2RlZyA8LSBmaWxlLnBhdGgoZGlybmFtZShnZXR3ZCgpKSwgImRlZ19icmFpbl9maWx0ZXJlZF9ieV9IR05DIikKb3V0cHV0X2Rpcl9oZ25jX2ZpbHRlcmVkX2RlZyA8LSBmaWxlLnBhdGgoZGlybmFtZShnZXR3ZCgpKSwgInBlcmljeXRlX0RFR19maWx0ZXJlZF9ieV9IR05DIikKZGlyLmNyZWF0ZShvdXRwdXRfZGlyX2hnbmNfZmlsdGVyZWRfZGVnLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKCiMgZWFjaCB0cmFuc3BvcnRlciBmYW1pbHkKdHJhbnNwb3J0ZXJfZGljdGlvbmFyeSA8LSBsaXN0KCkKZmlsZW5hbWVzIDwtIG5hbWVzKGhnbmNfZGZfbGlzdCkKI2ZpbGVuYW1lcyA8LSBjKCJHbHljaW5lX3JlY2VwdG9ycy5jc3YiKQpmb3IgKGZpbGVfbmFtZSBpbiBmaWxlbmFtZXMpIHsKICAKICAjID09PT09PT09PT09PT09PT09PT09PWludGVyc2VjdGlvbjogSEdOQyAmIGJyYWluPT09PT09PT09PT09PT09PT09PT09PT09CiAgIyBHZXQgdGhlIGN1cnJlbnQgdGFibGUKICB0cmFzcG9ydGVyX21hcF9pIDwtIGhnbmNfZGZfbGlzdFtbZmlsZV9uYW1lXV0KICAKICAjIENvbnZlcnQgdGhlIGludGVyZXN0IGNvbHVtbnMgdG8gY2hhcmFjdGVyCiAgZXhpc3RfY29scyA8LSBjb2xuYW1lcyh0cmFzcG9ydGVyX21hcF9pKVtjb2xuYW1lcyh0cmFzcG9ydGVyX21hcF9pKSAlaW4lIHJlcXVpcmVkX2NvbHNdCiAgdHJhc3BvcnRlcl9tYXBfaSA8LSB0cmFzcG9ydGVyX21hcF9pICU+JQogICAgbXV0YXRlKGFjcm9zcyhhbGxfb2YoZXhpc3RfY29scyksIGFzLmNoYXJhY3RlcikpCiAgCiAgIyBnZW5lcyBmcm9tIEhHTkMKICBnZW5lX3N5bWJvbHNfaGduY19pIDwtIHRyYXNwb3J0ZXJfbWFwX2kgJT4lCiAgICBzZWxlY3QoYWxsX29mKGV4aXN0X2NvbHMpKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCB2YWx1ZXNfdG8gPSAiZ2VuZSIpICU+JQogICAgc2VwYXJhdGVfcm93cyhnZW5lLCBzZXAgPSAiLFxccyoiKSAlPiUgICAjIFNwbGl0IGJ5IGNvbW1hIGFuZCByZW1vdmUgc3BhY2VzCiAgICBkaXN0aW5jdCgpICU+JSAgIyBSZW1vdmUgZHVwbGljYXRlIGVudHJpZXMKICAgIG5hLm9taXQoKSAgICAgICAjIFJlbW92ZSBOQSB2YWx1ZXMKICBnZW5lX3N5bWJvbHNfaGduY19pIDwtIHVuaXF1ZShnZW5lX3N5bWJvbHNfaGduY19pJGdlbmUpCgogICMgc2hhcmVkIHNsYwogIAogICN0cmFuc3BvcnRlcl90YXJnZXRzIDwtIGludGVyc2VjdCh0b2xvd2VyKGJyYWluLm1hcmtlcnMuc2FuZHJhJEdlbmUpLCB0b2xvd2VyKGdlbmVfc3ltYm9sc19oZ25jX2kpKQogIGJyYWluLnBlcmljeXRlLm1hcmtlcnMkR2VuZSA8LSByb3cubmFtZXMoYnJhaW4ucGVyaWN5dGUubWFya2VycykKICB0cmFuc3BvcnRlcl90YXJnZXRzIDwtIGludGVyc2VjdCh0b2xvd2VyKGJyYWluLnBlcmljeXRlLm1hcmtlcnMkR2VuZSksIHRvbG93ZXIoZ2VuZV9zeW1ib2xzX2hnbmNfaSkpCgogICMgRmlsdGVyIHRoZSB0YWJsZSBiYXNlZCBvbiBtYXRjaGVkIGdlbmVzCiAgI2ZpbHRlcmVkX3RhYmxlIDwtIGJyYWluLm1hcmtlcnMuc2FuZHJhICU+JQogICMgIGZpbHRlcih0b2xvd2VyKEdlbmUpICVpbiUgdHJhbnNwb3J0ZXJfdGFyZ2V0cykKICBmaWx0ZXJlZF90YWJsZSA8LSBicmFpbi5wZXJpY3l0ZS5tYXJrZXJzICU+JQogICAgZmlsdGVyKHRvbG93ZXIoR2VuZSkgJWluJSB0cmFuc3BvcnRlcl90YXJnZXRzKQogIAogICMgUmVzdG9yZSBvcmlnaW5hbCBjYXNlIGZvciBnZW5lIG5hbWVzCiAgI2ZpbHRlcmVkX3RhYmxlJGdlbmUgPC0gYnJhaW4ubWFya2Vycy5zYW5kcmEkR2VuZVticmFpbi5tYXJrZXJzLnNhbmRyYSRnZW5lICVpbiUgdHJhbnNwb3J0ZXJfdGFyZ2V0c10KICAKICBwcmludChnc3ViKCJcXC5jc3YkIiwgIiIsIGZpbGVfbmFtZSkpCiAgaWYgKGxlbmd0aChmaWx0ZXJlZF90YWJsZSRHZW5lKSA9PSAwKSB7CiAgICBuZXh0CiAgfQogIGNhdChwYXN0ZShjKGxlbmd0aChmaWx0ZXJlZF90YWJsZSRHZW5lKSwgImdlbmVzOiAiLHBhc3RlMChmaWx0ZXJlZF90YWJsZSRHZW5lLCAiICIpKSkpCgogICMgcmUtc2F2ZSB0aGUgbmV3IERFR3MgKHNoYXJlZCkKICBvdXRwdXRfZmlsZSA8LSBmaWxlLnBhdGgob3V0cHV0X2Rpcl9oZ25jX2ZpbHRlcmVkX2RlZywgcGFzdGUwKCJmaWx0ZXJlZF9icmFpbl9wY19ERUdzX2J5XyIsIGZpbGVfbmFtZSkpCiAgd3JpdGUuY3N2KGZpbHRlcmVkX3RhYmxlLCBvdXRwdXRfZmlsZSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgCiAgIyA9PT09PT09PT09PT09PT09PT09PT1wcmVwYXJlIHBsb3QgaW5wdXRzOiBvcmdhbnMgYW5kIGdlbmVzPT09PT09PT09PT09PT09PT09PT09PT09CiAgaWYgKGxlbmd0aChmaWx0ZXJlZF90YWJsZSRHZW5lKSA8IDI1KSB7CiAgICBmZWF0dXJlX2dlbmVzIDwtIGZpbHRlcmVkX3RhYmxlJEdlbmUKICB9IGVsc2UgewogICAgZmVhdHVyZV9nZW5lcyA8LSBmaWx0ZXJlZF90YWJsZSRHZW5lWzE6MjVdCiAgfQogIAogICMgQnJhaW4gc29ydGVkIHRvIHRvcAogIGNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhJG9yZ2FuX3NvcnRlZCA8LSBmYWN0b3IoY29tYmluZWRfY2VsbEBtZXRhLmRhdGEkb3JnYW4sIGxldmVscyA9IGMoIkJyYWluIiwgc2V0ZGlmZih1bmlxdWUoY29tYmluZWRfY2VsbEBtZXRhLmRhdGEkb3JnYW4pLCAiQnJhaW4iKSkpCgogICMgc29ydCBnZW5lcyBieSB1YmlxdWlvdXNuZXNzCiAgc29ydGVkX2ZlYXR1cmVfZ2VuZXMgPC0gc29ydF9nZW5lX2J5X3ViaXF1aXR5KGNvbWJpbmVkX2NlbGwsIGZlYXR1cmVfZ2VuZXMsIGZpbGVfbmFtZSkKICB0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5W1tnc3ViKCJcXC5jc3YkIiwgIiIsIGZpbGVfbmFtZSldXSA8LSBzb3J0ZWRfZmVhdHVyZV9nZW5lcwogIAogICMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1kb3QgcGxvdD09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgZ2VuZXJhdGVfZG90cGxvdChjb21iaW5lZF9jZWxsLCBzb3J0ZWRfZmVhdHVyZV9nZW5lcywgZmlsZV9uYW1lKQogIH0KYGBgCgoKYGBge3J9CnRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX3RhYmxlIDwtIHRyYW5zcG9ydGVyX2RpY3Rpb25hcnkKZm9yIChpIGluIG5hbWVzKHRyYW5zcG9ydGVyX2RpY3Rpb25hcnkpKSB7CiAgdHJhbnNwb3J0ZXJfZGljdGlvbmFyeV9mb3JfdGFibGVbW2ldXSA8LSBjYXQocGFzdGUwKHRyYW5zcG9ydGVyX2RpY3Rpb25hcnlbW2ldXSkpCn0KYGBgCgoKYGBge3J9CnRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSA8LSB0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5CiN0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5X2Zvcl9maWd1cmUkR1BDUiA8LSB0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5JEdQQ1JbMToxN10KCmlvbl9jaGFubmVsX2dlbmVzIDwtIGModHJhbnNwb3J0ZXJfZGljdGlvbmFyeV9mb3JfZmlndXJlJENhbGNpdW1fY2hhbm5lbHMsIHRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSRQb3Rhc3NpdW1fY2hhbm5lbHMsIHRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSRTb2RpdW1fY2hhbm5lbHMsIHRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSRUUlBfY2hhbm5lbHMpCmlvbl9jaGFubmVsX2dlbmVzIDwtIHVuaXF1ZShpb25fY2hhbm5lbF9nZW5lcykKaW9uX2NoYW5uZWxfZ2VuZXMgPC0gc29ydF9nZW5lX2J5X3ViaXF1aXR5KGNvbWJpbmVkX2NlbGwsIGlvbl9jaGFubmVsX2dlbmVzLCAieCIpCnRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSRpb25fY2hhbm5lbF9nZW5lcyA8LSBpb25fY2hhbm5lbF9nZW5lcwoKcmVjZXB0b3JfZ2VuZXMgPC0gYyh0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5JEFtaW5lX3JlY2VwdG9ycywgdHJhbnNwb3J0ZXJfZGljdGlvbmFyeSRDaG9saW5lcmdpY19yZWNlcHRvcnMsdHJhbnNwb3J0ZXJfZGljdGlvbmFyeSRHbHV0YW1hdGVfcmVjZXB0b3JzLCB0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5JEdseWNpbmVfcmVjZXB0b3JzKQpyZWNlcHRvcl9nZW5lcyA8LSB1bmlxdWUocmVjZXB0b3JfZ2VuZXMpCnJlY2VwdG9yX2dlbmVzIDwtIHNvcnRfZ2VuZV9ieV91YmlxdWl0eShjb21iaW5lZF9jZWxsLCByZWNlcHRvcl9nZW5lcywgIngiKQp0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5X2Zvcl9maWd1cmUkcmVjZXB0b3JfZ2VuZXMgPC0gcmVjZXB0b3JfZ2VuZXMKCnB1bXBfZ2VuZXMgPC0gYyh0cmFuc3BvcnRlcl9kaWN0aW9uYXJ5JEFCQ190cmFuc3BvcnRlcnMsIHRyYW5zcG9ydGVyX2RpY3Rpb25hcnkkQVRQYXNlKQpwdW1wX2dlbmVzIDwtIHVuaXF1ZShwdW1wX2dlbmVzKQpwdW1wX2dlbmVzIDwtIHNvcnRfZ2VuZV9ieV91YmlxdWl0eShjb21iaW5lZF9jZWxsLCBwdW1wX2dlbmVzLCAieCIpCnRyYW5zcG9ydGVyX2RpY3Rpb25hcnlfZm9yX2ZpZ3VyZSRwdW1wX2dlbmVzIDwtIHB1bXBfZ2VuZXMKCmdlbmVyYXRlX2RvdHBsb3QoY29tYmluZWRfY2VsbCwgaW9uX2NoYW5uZWxfZ2VuZXMsIHBhc3RlKCJwY19Jb25fQ2hhbm5lbHMuY3N2IikpCmdlbmVyYXRlX2RvdHBsb3QoY29tYmluZWRfY2VsbCwgcmVjZXB0b3JfZ2VuZXMsIHBhc3RlKCJwY19SZWNlcHRvcnMuY3N2IikpCmdlbmVyYXRlX2RvdHBsb3QoY29tYmluZWRfY2VsbCwgdHJhbnNwb3J0ZXJfZGljdGlvbmFyeV9mb3JfZmlndXJlJEdQQ1IsIHBhc3RlKCJwY19HUENSLmNzdiIpKQpnZW5lcmF0ZV9kb3RwbG90KGNvbWJpbmVkX2NlbGwsIHB1bXBfZ2VuZXMsIHBhc3RlKCJwY19QdW1wLmNzdiIpKQoKCmBgYAoKCgoKYGBge3J9CiMgaW50ZXJzY3Rpb246IGdlbmVfc3ltYm9sc19zbGMgJiBicmFpbi5tYXJrZXJzLnNhbmRyYQpzbGNfdGFyZ2V0cy5zYW5kcmEgPC0gaW50ZXJzZWN0KHRvbG93ZXIoZ2VuZV9zeW1ib2xzX3NsYyksIHRvbG93ZXIoYnJhaW4ubWFya2Vycy5zYW5kcmEkR2VuZSkpCmZpbHRlcmVkLmJyYWluLm1hcmtlcnMuc2FuZHJhIDwtIGJyYWluLm1hcmtlcnMuc2FuZHJhICU+JSBmaWx0ZXIodG9sb3dlcihHZW5lKSAlaW4lIHNsY190YXJnZXRzLnNhbmRyYSkKc2xjX3RhcmdldHMuc2FuZHJhIDwtIGZpbHRlcmVkLmJyYWluLm1hcmtlcnMuc2FuZHJhJEdlbmUKd3JpdGUuY3N2KGZpbHRlcmVkLmJyYWluLm1hcmtlcnMuc2FuZHJhLCAiZmlsdGVyZWRfQnJhaW5fRUNfbWFya2Vyc19mYzFfcGFkajAwNS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQoKIyBkb3QgcGxvdCBvZiB0aGUgZXhwcmVzc2lvbnMKZG90X3Bsb3QgPC0gRG90UGxvdChjb21iaW5lZF9jZWxsLCBmZWF0dXJlcyA9IHNsY190YXJnZXRzLnNhbmRyYVsxOjI3XSwgZ3JvdXAuYnkgPSAib3JnYW4iKSArCiAgbGFicyh4ID0gIk9yZ2FuIiwgeSA9ICJHZW5lIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBjb29yZF9mbGlwKCkKZ2dzYXZlKCJkb3RfcGxvdF9icmFpbi5wZGYiLCBwbG90ID0gZG90X3Bsb3QsIHdpZHRoID0gNywgaGVpZ2h0ID0gMTApCmBgYAoKCgoKCiMjIHNjIGFuYWx5c2lzCmBgYHtyfQpteTM2Y29sb3JzIDwtIGMoJyNFNUQyREQnLCAnIzUzQTg1RicsICcjRjFCQjcyJywgJyNGM0IxQTAnLCAnI0Q2RTdBMycsICcjNTdDM0YzJywgJyM1RjNENjknLCAnI0M1REVCQScsICcjNThBNEMzJywgJyNFNEM3NTUnLCAnI0Y3RjM5OCcsJyM1ODU2NTgnLAogICAgICAgICAnI0FBOUE1OScsICcjRTYzODYzJywnI0U5NUM1OScsICcjRTU5Q0M0JywgJyNBQjMyODInLCAnIzIzNDUyRicsICcjQkQ5NTZBJywgJyM4QzU0OUMnLCAnIzQ3NkQ4NycsCiAgICAgICAgICcjOUZBM0E4JywgJyNFMEQ0Q0EnLCAnI0UzOUEzNScsICcjQzFFNkYzJywgJyM2Nzc4QUUnLCAnIzkxRDBCRScsICcjQjUzRTJCJywKICAgICAgICAgJyM3MTI4MjAnLCAnI0RDQzFERCcsICcjQ0NFMEY1JywgJyNDQ0M5RTYnLCAnIzYyNUQ5RScsICcjNjhBMTgwJywgJyMzQTY5NjMnLAogICAgICAgICAnIzk2ODE3NScpCgpEaW1QbG90KGNvbWJpbmVkX2NlbGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAib3JnYW4iLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSxjb2xzID0gbXkzNmNvbG9ycykKYGBgCgojIyBkZWcgYW5hbHlzaXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHJlYWRyKQoKIyBicmFpbiBzbGMgZGVncwpicmFpbl9zbGNfZGVncyA8LSByZWFkX2Nzdigifi9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1zY2hlbjYwMUB1c2MuZWR1L015IERyaXZlL3RyYW5zcG9ydG9yL2RlZ19TTEMvQnJhaW4uY3N2IikKCnBsb3RfZ2VuZSA8LSBicmFpbl9zbGNfZGVnc1ssYygiY2x1c3RlciIsIi4uLjEiKV0KY29sbmFtZXMocGxvdF9nZW5lKVtjb2xuYW1lcyhwbG90X2dlbmUpID09ICIuLi4xIl0gPC0gImdlbmUiCnBsb3RfZ2VuZSRnZW5lIDwtIHN1YigiXFwuLioiLCAiIiwgcGxvdF9nZW5lJGdlbmUpCgojcGxvdF9nZW5lIDwtIHBsb3RfZ2VuZVsxOjIwLF0KYGBgCgpgYGB7cn0KcGN0X3RocmVzIDwtIDAuMgpmY190aHJlcyA8LSAwLjIKcHYgPC0gMC4wNQoKYnJhaW5fc2xjX2RlZ3NfZmlsdGVyZWQgPC0gYnJhaW5fc2xjX2RlZ3NbKGJyYWluX3NsY19kZWdzJHBfdmFsPHB2ICYgYWJzKGJyYWluX3NsY19kZWdzJGF2Z19sb2cyRkMpID4gZmNfdGhyZXMpLF0KCgpicmFpbl9zbGNfZGVnc19maWx0ZXJlZCA8LSBicmFpbl9zbGNfZGVnc19maWx0ZXJlZFsoKChicmFpbl9zbGNfZGVnc19maWx0ZXJlZCRhdmdfbG9nMkZDID4gZmNfdGhyZXMpJihicmFpbl9zbGNfZGVnc19maWx0ZXJlZCRwY3QuMT5wY3RfdGhyZXMpKXwoKGJyYWluX3NsY19kZWdzX2ZpbHRlcmVkJGF2Z19sb2cyRkMgPCAtZmNfdGhyZXMpJihicmFpbl9zbGNfZGVnc19maWx0ZXJlZCRwY3QuMj5wY3RfdGhyZXMpKSksXQoKCnBsb3RfZ2VuZSA8LSBicmFpbl9zbGNfZGVnc19maWx0ZXJlZFssYygiY2x1c3RlciIsIi4uLjEiKV0KY29sbmFtZXMocGxvdF9nZW5lKVtjb2xuYW1lcyhwbG90X2dlbmUpID09ICIuLi4xIl0gPC0gImdlbmUiCnBsb3RfZ2VuZSRnZW5lIDwtIHN1YigiXFwuLioiLCAiIiwgcGxvdF9nZW5lJGdlbmUpCmBgYAoKIyB2aW9saW4KYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShncmlkRXh0cmEpCgojIERlZmluZSBvdXRwdXQgUERGIGZpbGUKcGRmKCJicmFpbl9kZWdfdmlvbGluX3Bsb3QucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA2KSAgIyBBZGp1c3Qgd2lkdGggJiBoZWlnaHQgYXMgbmVlZGVkCgojIFNldCB1cCBwbG90IGNvdW50ZXIKcGxvdF9saXN0IDwtIGxpc3QoKQpwbG90X2NvdW50IDwtIDAKcGxvdHNfcGVyX3BhZ2UgPC0gNCAgIyAyKjIgZ3JpZCBwZXIgcGFnZQoKIyBHZW5lcmF0ZSB2aW9saW4gcGxvdHMKY2FuZGlkYXRlcyA8LSBwbG90X2dlbmUkZ2VuZQpjYW5kaWRhdGVzIDwtIGMoZGVnX3ZfcGxvdDEsZGVnX3ZfcGxvdDIsZGVnX3ZfcGxvdDMpCgpmb3IgKGdlbmUgaW4gY2FuZGlkYXRlcykgewogIGlmIChnZW5lICVpbiUgcm93bmFtZXMoY29tYmluZWRfY2VsbCkpIHsgICMgRW5zdXJlIHRoZSBnZW5lIGV4aXN0cyBpbiB0aGUgZGF0YQogICAgcCA8LSBWbG5QbG90KGNvbWJpbmVkX2NlbGwsIGZlYXR1cmVzID0gZ2VuZSwgZ3JvdXAuYnkgPSAib3JnYW4iLCBwdC5zaXplID0gMC4xKSArCiAgICAgIGdndGl0bGUoZ2VuZSkgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gOCkpCgogICAgcGxvdF9saXN0W1tsZW5ndGgocGxvdF9saXN0KSArIDFdXSA8LSBwCiAgICBwbG90X2NvdW50IDwtIHBsb3RfY291bnQgKyAxCgogICAgIyBXaGVuIHJlYWNoaW5nIDkgcGxvdHMsIHByaW50IHRoZSBwYWdlCiAgICBpZiAocGxvdF9jb3VudCAlJSBwbG90c19wZXJfcGFnZSA9PSAwIHx8IGdlbmUgPT0gdGFpbChjYW5kaWRhdGVzLCAxKSkgewogICAgICBkby5jYWxsKGdyaWQuYXJyYW5nZSwgYyhwbG90X2xpc3QsIG5jb2wgPSAyLCBucm93ID0gMikpCiAgICAgIHBsb3RfbGlzdCA8LSBsaXN0KCkgICMgUmVzZXQgcGxvdCBsaXN0CiAgICB9CiAgfQp9CgojIENsb3NlIHRoZSBQREYgZmlsZQpkZXYub2ZmKCkKCmBgYAoKIyBicmVhayBwZGYKYGBge3J9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyeQpsaWJyYXJ5KHBkZnRvb2xzKQoKIyBEZWZpbmUgaW5wdXQgUERGIGZpbGUKaW5wdXRfcGRmIDwtICJyYXdfdmlvbGluX3Bsb3RzLnBkZiIgICMgUmVwbGFjZSB3aXRoIHlvdXIgYWN0dWFsIFBERiBmaWxlCgojIFJlYWQgdGhlIG51bWJlciBvZiBwYWdlcyBpbiB0aGUgUERGCnRvdGFsX3BhZ2VzIDwtIHBkZl9pbmZvKGlucHV0X3BkZikkcGFnZXMgICMgU2hvdWxkIGJlIDI2CgojIERlZmluZSBvdXRwdXQgZmlsZSBuYW1lcwpvdXRwdXRfZmlsZXMgPC0gYygicmF3X3Zpb2xpbl9wYXJ0MS5wZGYiLCAicmF3X3Zpb2xpbl9wYXJ0Mi5wZGYiLCAicmF3X3Zpb2xpbl9wYXJ0My5wZGYiLCAicmF3X3Zpb2xpbl9wYXJ0NC5wZGYiKQoKIyBEZWZpbmUgcGFnZSBzcGxpdHMgKGZpcnN0IDYsIG5leHQgNiwgbmV4dCA2LCBsYXN0IDgpCnBhZ2Vfc3BsaXRzIDwtIGxpc3QoMTo2LCA3OjEyLCAxMzoxOCwgMTk6MjYpCgojIExvb3AgdGhyb3VnaCBlYWNoIHN1YnNldCBhbmQgc2F2ZSB0byBhIG5ldyBQREYKZm9yIChpIGluIHNlcV9hbG9uZyhvdXRwdXRfZmlsZXMpKSB7CiAgcGRmX3N1YnNldChpbnB1dF9wZGYsIHBhZ2VzID0gcGFnZV9zcGxpdHNbW2ldXSwgb3V0cHV0ID0gb3V0cHV0X2ZpbGVzW2ldKQogIG1lc3NhZ2UoIlNhdmVkOiAiLCBvdXRwdXRfZmlsZXNbaV0pCn0KYGBgCgoKYGBge3J9CiMgc2VsZgpkZWdfdl9wbG90MSA8LSBjKCJTbGNvMWMxIiwgIlNsYzIyYTgiLCAiU2xjMzhhMyIsICJTbGMzOGE1IiwgIlNsYzFhMSIsICJTbGMxOWEzIiwgIlN0cmE2IiwiU2xjNmExMyIsIlNsYzM4YTUiKQoKI3NoYXJlZCB3aXRoIFRlc3RpcwpkZWdfdl9wbG90MiA8LSBjKCJNZnNkMmEiLCAiU2xjN2E1IiwgIlNsYzE2YTQiLCAiTWZzZDdjIiwiU2xjMzVmMiIsICJTbGMxOWEzIiwgIk1mc2Q3YyIsICJTbGMzNWYyIikKCiN3LyBibGFkZGVyCmRlZ192X3Bsb3QzIDwtIGMoIlNsYzM4YTExIiwgIlNsYzVhNSIpCgoKYGBgCgojIHdoaWNoIGNhbmRpZGF0ZSBmdWxseSBzaG93IHVwCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyeQpsaWJyYXJ5KGRwbHlyKQoKIyBEZWZpbmUgdGhlIGxpc3Qgb2YgY2FuZGlkYXRlIGdlbmVzIChyZXBsYWNlIHdpdGggeW91ciBhY3R1YWwgbGlzdCkKY2FuZGlkYXRlcyA8LSBjKGRlZ192X3Bsb3QxLCBkZWdfdl9wbG90MiwgZGVnX3ZfcGxvdDMpICAjIEV4YW1wbGUgY2FuZGlkYXRlIGdlbmVzCgojIERlZmluZSB0aGUgcmVxdWlyZWQgb3JnYW4gY29uZGl0aW9ucwpyZXF1aXJlZF9vcmdhbnMgPC0gYygiQnJhaW4iLCAiQmxhZGRlciIsICJMaXZlciIsICJIZWFydCIsICJJbnRlc3RpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQ29sb24iLCAiVGVzdGlzIiwgIk11c2NsZSIsICJMdW5nIiwgIlNwbGVlbiIsICJLaWRuZXkiKQoKIyBGaWx0ZXIgZm9yIGNhbmRpZGF0ZSBnZW5lcyBvbmx5CmFsbC5tYXJrZXJzLmZpbHRlcmVkLmJ5LmNhbmRpZGF0ZXMgPC0gYWxsLm1hcmtlcnMgJT4lCiAgZmlsdGVyKGdlbmUgJWluJSBjYW5kaWRhdGVzKQoKIyBDb3VudCBob3cgbWFueSB1bmlxdWUgb3JnYW5zIGVhY2ggZ2VuZSBhcHBlYXJzIGluCmdlbmVfb3JnYW5fY291bnQgPC0gYWxsLm1hcmtlcnMuZmlsdGVyZWQuYnkuY2FuZGlkYXRlcyAlPiUKICBncm91cF9ieShnZW5lKSAlPiUKICBzdW1tYXJpemUob3JnYW5zX3ByZXNlbnQgPSBsaXN0KHVuaXF1ZShjbHVzdGVyKSksIGNvdW50ID0gbigpKQoKIyBDaGVjayB3aGljaCBnZW5lcyBhcHBlYXIgaW4gKiphbGwgMTAgb3JnYW5zKioKZ2VuZXNfZnVsbHlfcHJlc2VudCA8LSBnZW5lX29yZ2FuX2NvdW50ICU+JQogIGZpbHRlcihhbGwocmVxdWlyZWRfb3JnYW5zICVpbiUgb3JnYW5zX3ByZXNlbnQpKSAlPiUKICBwdWxsKGdlbmUpICAjIEV4dHJhY3QgdGhlIGdlbmUgbmFtZXMKCiMgUHJpbnQgcmVzdWx0cwpwcmludCgiR2VuZXMgZm91bmQgaW4gYWxsIDEwIG9yZ2FuczoiKQpwcmludChnZW5lc19mdWxseV9wcmVzZW50KQpgYGAKCgojIGRvdCBwbG90CmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkoZ2dwbG90MikKI2xpYnJhcnkoZHBseXIpCgojIFRyYW5zZm9ybSBwLXZhbHVlCmRlZ190YWJsZSA8LSBhbGwubWFya2Vycy5maWx0ZXJlZC5ieS5jYW5kaWRhdGVzICU+JQogIG11dGF0ZShwX3NpemUgPSAtbG9nMTAocF92YWwrMC4wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxKSkgICMgVHJhbnNmb3JtIFAtdmFsdWUKCiMgQ3JlYXRlIHRoZSBkb3QgcGxvdApkb3RfcGxvdCA8LSBnZ3Bsb3QoZGVnX3RhYmxlLCBhZXMoeCA9IGNsdXN0ZXIsIHkgPSBnZW5lKSkgKwogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwX3NpemUsIGNvbG9yID0gYXZnX2xvZzJGQykpICsgICMgRG90IHNpemUgPSAtbG9nMTAocF92YWwpLCBDb2xvciA9IGxvZzJGQwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMSwgOCkpICsgICMgQWRqdXN0IGRvdCBzaXplIHJhbmdlCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDApICsgICMgQ29sb3IgZ3JhZGllbnQKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoeCA9ICJPcmdhbiIsIHkgPSAiR2VuZSIsIHNpemUgPSAiLWxvZzEwKFAtdmFsdWUpIiwgY29sb3IgPSAiTG9nMiBGb2xkIENoYW5nZSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyBEaXNwbGF5IHRoZSBwbG90CnByaW50KGRvdF9wbG90KQpgYGAKCgojIEJyYWluIG1hcmtlcnMKCgojIGhlYXRtYXAKYGBge3J9CkRvSGVhdG1hcChvYmplY3QgPSBjb21iaW5lZF9obSwgZmVhdHVyZXMgPSBmZWF0dXJlcywgc2xvdCA9ICJkYXRhIiwgZ3JvdXAuY29sb3JzID0gbXkzNmNvbG9ycykrIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoJyMzYjY5YjUnLCAgIndoaXRlIiwgJyNiNTNiM2InKSkKYGBgCgoKCgpgYGB7cn0KI3Bsb3RfZ2VuZSA8LSByZWFkX2V4Y2VsKCJwbG90Z2VuZS54bHN4IikKcGxvdF9nZW5lJGNsdXN0ZXI9ZmFjdG9yKHBsb3RfZ2VuZSRjbHVzdGVyLGxldmVscyA9IHVuaXF1ZShwbG90X2dlbmUkY2x1c3RlcikpCnBsb3RfZ2VuZSA8LSBwbG90X2dlbmUlPiVhcnJhbmdlKGNsdXN0ZXIsZ2VuZSkKCmNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhJGNlbGxfdHlwZT1mYWN0b3IoY29tYmluZWRfY2VsbEBtZXRhLmRhdGEkY2VsbF90eXBlLGxldmVscyA9IGxldmVscyhwbG90X2dlbmUkY2x1c3RlcikpCmBgYAoKYGBge3J9CmNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhJENCPXJvd25hbWVzKGNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhKQojaW50ZWdyYXRlZEBtZXRhLmRhdGE9aW50ZWdyYXRlZEBtZXRhLmRhdGElPiVpbm5lcl9qb2luKGludGVncmF0ZWQsYnk9IkNCIikKcm93bmFtZXMoY29tYmluZWRfY2VsbEBtZXRhLmRhdGEpPWNvbWJpbmVkX2NlbGxAbWV0YS5kYXRhJENCCmBgYAoKCmBgYHtyfQpjb2xvcl9jdD1jKGJyZXdlci5wYWwoMTIsICJTZXQzIilbLWMoMiwzLDksMTIpXSwiI2IzYjNiMyIsCiAgICAgICAgICAgYnJld2VyLnBhbCg1LCAiU2V0MSIpWzJdLAogICAgICAgICAgIGJyZXdlci5wYWwoMywgIkRhcmsyIilbMV0sCiAgICAgICAgICAgIiNmYzRlMmEiLCIjZmI5YTk5IiwiI2Y3ODFiZiIsIiNlNzI5OGEiKQpuYW1lcyhjb2xvcl9jdCk9bGV2ZWxzKHBsb3RfZ2VuZSRjbHVzdGVyKQoKIyMjIOS4u+S7o+eggSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiN2bG4uZGY9YXMuZGF0YS5mcmFtZShpbnRlZ3JhdGVkW1siUk5BIl1dQGRhdGFbcGxvdF9nZW5lJGdlbmUsXSkKdmxuLmRmPWFzLmRhdGEuZnJhbWUoYXMuZGF0YS5mcmFtZShhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkX2NlbGxbWyJSTkEiXV0sIHNsb3QgPSAiZGF0YSIpKSlbcGxvdF9nZW5lJGdlbmUsIF0pCnZsbi5kZiRnZW5lPXJvd25hbWVzKHZsbi5kZikKdmxuLmRmPW1lbHQodmxuLmRmLGlkPSJnZW5lIikKY29sbmFtZXModmxuLmRmKVtjKDIsMyldPWMoIkNCIiwiZXhwIikKCmFubm89Y29tYmluZWRfY2VsbEBtZXRhLmRhdGFbLGMoIkNCIiwiY2VsbF90eXBlIildCnZsbi5kZj1pbm5lcl9qb2luKHZsbi5kZixhbm5vLGJ5PSJDQiIpCnZsbi5kZiRnZW5lPWZhY3Rvcih2bG4uZGYkZ2VuZSxsZXZlbHMgPSBwbG90X2dlbmUkZ2VuZSkKdmxuLmRmIDwtIHZsbi5kZlshaXMubmEodmxuLmRmJGNlbGxfdHlwZSksIF0KYGBgCgpgYGB7cn0KIyDlvZPkvaDmg7Pnq5bnm7TmlrnlkJHmjpLniYjov5nlvKDlm77niYfml7bvvJoKdmxuLmRmJT4lZ2dwbG90KGFlcyhjZWxsX3R5cGUsZXhwKSkrCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9Y2VsbF90eXBlKSxzY2FsZSA9ICJ3aWR0aCIpKyAKICAj5aaC5p6c5oOz5pyA57uI5ZGI546w5Ye65p2l55qE5Zu+77yM5piv5qC55o2u5Z+65Zug5raC6Imy55qE77yM5Lmf5bCx5piv5LiA5Liq5Z+65Zug5LiA56eN6aKc6Imy77yM5bqU5pS55Li677yaYWVzKGZpbGw9Z2VuZSkKICAj5LiA6Iis6ICM6KiA77yM5Z+65Zug5pWw5aSa5LqO57uG6IOe57G75Z6L5pWw77yM5b2T5qC55o2u5Z+65Zug5raC6Imy5pe277yM6YWN6Imy5pa55qGI5pyJ54K557mB55CQ77yM5omA5Lul5LiN5o6o6I2QYWVzKGZpbGw9Z2VuZSkKICBmYWNldF9ncmlkKGdlbmV+LixzY2FsZXMgPSAiZnJlZV95IikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfY3QpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgCiAgICBheGlzLnRpdGxlLnguYm90dG9tID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54LmJvdHRvbSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54LmJvdHRvbSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LGhqdXN0ID0gMSx2anVzdCA9IE5VTEwsY29sb3IgPSAiYmxhY2siLHNpemUgPSAxNCksCiAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueS5sZWZ0ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgCiAgICBwYW5lbC5zcGFjaW5nLnkgPSB1bml0KDAsICJjbSIpLAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTAsc2l6ZSA9IDE0LGhqdXN0ID0gMCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCmdnc2F2ZSgiYnJhaW5fc2xjX21hcmtlcnMucGRmIixkZXZpY2UgPSAicGRmIix3aWR0aCA9IDE4LGhlaWdodCA9IDkwLHVuaXRzID0gImNtIikKYGBg